﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CCPnuts.ISkyDiskFileSystem.Interfaces;
using CCPnuts.Pack;
using CCPnuts.ISkyDiskFileSystem.Exceptions;

namespace CCPnuts.ISkyDiskFileSystem
{
    public abstract class SkyElementContainer : SkyElement
    {
        #region Packed Target

        internal SkyElementContainer(IPacked packed) : base(packed) { }

        internal new I_SkyElementContainer Packed { get { return (I_SkyElementContainer)base.Packed; } }

        #endregion

        #region Proxy Members

        #region Essential Members

        #region Modify Methods

        /// <summary>
        /// upload a file to this container
        /// </summary>
        /// <param name="path"></param>
        public Uploader UploadFile(string path)
        {
            return (Uploader)Util.NNTar(Packed.UploadFile(path));
        }

        /// <summary>
        /// delete a element from this container
        /// </summary>
        /// <param name="element"></param>
        public void Delete(SkyElement element)
        {
            Packed.Delete((I_SkyElement)Util.NNTar(element));
        }

        /// <summary>
        /// delete a file with the given name
        /// </summary>
        /// <param name="fileName"></param>
        public void DeleteFile(string fileName)
        {
            Packed.DeleteFile(fileName);
        }

        /// <summary>
        /// delete a directory with the given name
        /// </summary>
        /// <param name="dirName"></param>
        public void DeleteDir(string dirName)
        {
            Packed.DeleteDir(dirName);
        }

        /// <summary>
        /// create a dir
        /// </summary>
        /// <param name="dirName"></param>
        public void CreateDir(string dirName)
        {
            Packed.CreateDir(dirName);
        }

        #endregion

        #region Properties

        /// <summary>
        /// get the collection of child
        /// </summary>
        public SkyElementCollection Children { get { return (SkyElementCollection)Util.NNTar(Packed.Children); } }

        #endregion

        #endregion

        #region Optional Members

        /// <summary>
        /// [Optional]Gets the target path
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        [Optional]
        public SkyElementContainer this[string path]
        {
            get
            {
                try { return (SkyElementContainer)Util.NNTar(Packed[path]); }
                catch (NotImplementedException)
                {
                    var sl = path.Split('/', '\\');
                    var dir = this;
                    foreach (var s in sl)
                    {
                        if (s == "..") { dir = dir.Parent; }
                        else if (s != "" && s != ".") { dir = dir.GetDir(s); }
                    }
                    return dir;
                }
            }
        }

        /// <summary>
        /// [Optional]Gets the target file
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        [Optional]
        public SkyFile this[string path, string fileName]
        {
            get
            {
                try { return (SkyFile)Util.NNTar(Packed[path, fileName]); }
                catch (NotImplementedException)
                {
                    var dir = this[path];
                    return dir.GetFile(fileName);
                }
            }
        }

        /// <summary>
        /// [Optional]Gets the directory in its children by its name
        /// </summary>
        /// <param name="dirName"></param>
        /// <returns>directory; null if not found</returns>
        [Optional]
        public SkyDirectory GetDir(string dirName)
        {
            try { return (SkyDirectory)Util.NNTar(Packed.GetDir(dirName)); }
            catch (NotImplementedException)
            {
                var res = from item in Children
                          where item.ElementType == SkyElementTypes.Directory && item.Name == dirName
                          select item;

                if (res.Count() != 1)
                {
                    throw new SkyElementNotFoundException(String.Format("The Directory : {0} can not be found.", dirName));
                }
                return res.First() as SkyDirectory;
            }
        }

        /// <summary>
        /// [Optional]Check if there is such a directory
        /// </summary>
        /// <param name="dirName"></param>
        /// <returns></returns>
        [Optional]
        public bool HasDir(string dirName)
        {
            try { return Packed.HasDir(dirName); }
            catch (NotImplementedException)
            {
                var res = from item in Children
                          where item.ElementType == SkyElementTypes.Directory && item.Name == dirName
                          select item;

                return res.Count() > 0;
            }
        }

        /// <summary>
        /// [Optional]Gets the file in its children by its name
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns>file; null if not found</returns>
        [Optional]
        public SkyFile GetFile(string fileName)
        {
            try { return (SkyFile)Util.NNTar(Packed.GetFile(fileName)); }
            catch (NotImplementedException)
            {
                var res = from item in Children
                          where item.ElementType == SkyElementTypes.File && item.Name == fileName
                          select item;

                if (res.Count() != 1)
                {
                    throw new SkyElementNotFoundException(String.Format("The Directory : {0} can not be found.", fileName));
                }
                return res.First() as SkyFile;
            }
        }

        /// <summary>
        /// [Optional]Check if there is such a file
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        [Optional]
        public bool HasFile(string fileName)
        {
            try { return Packed.HasFile(fileName); }
            catch (NotImplementedException)
            {
                var res = from item in Children
                          where item.ElementType == SkyElementTypes.File && item.Name == fileName
                          select item;

                return res.Count() > 0;
            }
        }

        /// <summary>
        /// Upload a directory. This is a Optional method.
        /// </summary>
        /// <param name="dirpath"></param>
        /// <returns></returns>
        [Optional]
        public bool UploadDirectory(string dirpath)
        {
            try { return Packed.UploadDirectory(dirpath); }
            catch (NotImplementedException)
            {
                throw new NotSupportedException();
            }
        }

        #endregion

        #endregion
    }
}
